
#include <iostream>
#include <pthread.h>
#include "CThreadPool.h"
#include <sys/time.h>

using namespace std;

CThreadPool::CThreadPool()
{
  CThreadPool(10, 3, 8, 5);
}

CThreadPool::CThreadPool(int iMaxNum, int iAvailLow, int iAvailHigh, int iInitNum)
{
	//m_iAvailNum = 0;
  m_iMaxNum = iMaxNum;
  m_iAvailLow = iAvailLow;
  m_iInitNum  = iInitNum;
  m_iAvailHigh = iAvailHigh;
  
  m_BusyList.clear();
  m_IdleList.clear();
  for(int i = 0; i < m_iInitNum; i++)
  {
    CWorkerThread* thr = new CWorkerThread(false);
    thr->SetThreadPool(this);
    thr->Start();
    AppendToIdleList(thr);
  }
}

CThreadPool::~CThreadPool()
{
  //TerminateAll();
}

void CThreadPool::TerminateAll()
{
  for(int i = 0; i < m_ThreadList.size(); i++)
  {
    CWorkerThread* thr = m_ThreadList[i];
    //thr->Join();
    if(thr != NULL)
    {
      thr->Terminate();
      thr->Join();
      delete thr;
    }
  }
  m_ThreadList.clear();
  m_BusyList.clear();
  m_IdleList.clear();
  return;
}

CWorkerThread* CThreadPool::GetIdleThread()
{
	CWorkerThread* thr = NULL;
	//int iAvailNum = 0;
	/*
	m_IdleMutex.Lock();
  //while(m_IdleList.size() == 0)
  if(m_iAvailNum == 0)
  {
  	m_IdleMutex.Unlock();
  	m_IdleCondMutex.Lock();
    m_IdleCond.Wait(&m_IdleCondMutex);
    m_IdleCondMutex.Unlock();
  }
  else
  {
    m_IdleMutex.Unlock();
  }*/
  
  m_IdleMutex.Lock();
  cout << "CThreadPool::IdleNum="<<GetIdlNum()<< " busynum="<<GetBusyNum()<<endl;
  if(GetIdlNum() > 0)
  {
    thr = (CWorkerThread*)m_IdleList.front();
    m_IdleList.erase(m_IdleList.begin());
  }
  else
  {
    thr = NULL;
  }
 
  m_IdleMutex.Unlock();
  return thr;
}

void CThreadPool::AppendToIdleList(CWorkerThread* jobthread)
{
  m_IdleMutex.Lock();
  m_IdleList.push_back(jobthread);
  m_ThreadList.push_back(jobthread);
  //m_iAvailNum++;
  //KdLog.DebugLog(__FILE__, __LINE__,"aaaam_iAvailNum = %d\n", m_iAvailNum);
  m_IdleMutex.Unlock();
}

void CThreadPool::MoveToBusyList(CWorkerThread* idlethread)
{  
  m_BusyMutex.Lock();
  if(idlethread != NULL)
  {
    m_BusyList.push_back(idlethread);
  }
  m_BusyMutex.Unlock();
}

void CThreadPool::MoveToIdleList(CWorkerThread* busythread)
{
	//printf("MoveToIdleList[%d]\n", busythread->m_tThread);
  m_BusyMutex.Lock();
  vector<CWorkerThread*>::iterator pos;
  pos = find(m_BusyList.begin(), m_BusyList.end(), busythread);
  if(pos != m_BusyList.end())
  {
    m_BusyList.erase(pos);	
  }
  else
  {
    ;//printf("Move To Idle List failure===========\n");
  }
  m_BusyMutex.Unlock();
  
  m_IdleMutex.Lock();
  m_IdleList.push_back(busythread);
  //m_iAvailNum++;
  //printf("insert idlelist[%d]\n",busythread);
  //cout<<"CThreadPool::MoveToIdleList thid="<<(long)(busythread->GetThreadId())<<endl;
  m_IdleMutex.Unlock();
   
  //m_IdleCond.Signal();
}

void CThreadPool::CreateIdleThread(int num)
{
  for(int i = 0; i< num; i++)
  {
    CWorkerThread* thr = new CWorkerThread(false);
    thr->SetThreadPool(this);
    thr->Start();
    AppendToIdleList(thr);
  }
}

void CThreadPool::DeleteIdleThread(int num)
{
	CWorkerThread* thr = NULL;
  m_IdleMutex.Lock();
  for(int i = 0; i < num; i++)
  {
    if(m_IdleList.size() > 0)
    {
      thr = (CWorkerThread*)m_IdleList.back();
      //m_IdleList.erase(m_IdleList.begin());
      m_IdleList.pop_back();
      thr->Terminate();
    } 
    else
    {
    	m_IdleMutex.Unlock();
    	return;
    }
    
    vector<CWorkerThread*>::iterator pos1;
    pos1 = find(m_ThreadList.begin(), m_ThreadList.end(), thr);
    if(pos1 != m_ThreadList.end())
    {
    	//printf("CThreadPool::DeleteIdleThread:m_ThreadList[%d]\n", thr->m_tThread);
      m_ThreadList.erase(pos1);
    }
    
    if(thr != NULL) 
    {
    	thr->Join();
    	//usleep(2000);
    	delete thr;
    	thr = NULL;
    }
  }
  m_IdleMutex.Unlock();
}

int CThreadPool::Run(CJob* job, void* jobdata)
{
  int iAvailNum = 0;
  
  /*
  m_BusyMutex.Lock();
  if(GetBusyNum() == m_iMaxNum)
  {
  	m_BusyMutex.Unlock();
  	cout <<"CThreadPool::no more thread create"<<endl;
  	return -1;
  }
  m_BusyMutex.Unlock();*/
  
  m_IdleMutex.Lock();
  iAvailNum = GetIdlNum();
  m_IdleMutex.Unlock();
  if(iAvailNum < m_iAvailLow)
  {
    if(GetAllNum() + m_iInitNum - iAvailNum < m_iMaxNum)
    {
    	//printf("create1===================\n");
    	CreateIdleThread(m_iInitNum - iAvailNum);
    }
    else
    {
    	//printf("CreateIdleThread2=%d==========\n", m_iMaxNum - GetAllNum());
      CreateIdleThread(m_iMaxNum - GetAllNum());
    }
  }
  else if(iAvailNum > m_iAvailHigh)
  {
      DeleteIdleThread(1);
      //cout<<"AvailHigh="<<m_iAvailHigh<<";AvailNum="<<iAvailNum<<endl;
  }

  CWorkerThread* idlethr = GetIdleThread();
  if(idlethr != NULL)
  {
    MoveToBusyList(idlethr);
    idlethr->SetJob(job, jobdata);
  }
  else
  {
  	cout <<"CThreadPool::no idle thread"<<endl;
  	return -1;
  }
  return 0;
}